/*
 * @(#)EmailMessageSenderComparator.java
 *
 * Copyright (c) 2004 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */

package com.dcivision.upgrade.handler;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dcivision.upgrade.UpgradeContext;
import com.dcivision.upgrade.UpgradeException;
import com.dcivision.upgrade.UpgradeExceptionHandler;
import com.dcivision.upgrade.UpgradeState;

/**
 * This class present composite and leaf role of compsite design pattern, and
 * common operation have been implements for compsite in method
 * {@link #upgrade()}, every sub class's actually operation should writed in
 * method {@link #upgradeBegin()} and {@link #upgradeEnd()}.
 * 
 * @author      Brook.Huang
 * @company     DCIVision Limited
 * @creation    19/04/2007
 * @version     $Revision: 1.2 $
 */
public abstract class UpgradeHandlerBase implements UpgradeHandler {

  protected Log log = LogFactory.getLog(UpgradeHandlerBase.class);

  protected List upgradeHandlersList = new ArrayList();

  protected List upgradeExceptionHandlersList = null;

  protected UpgradeContext upgradeContext = null;

  public UpgradeHandlerBase(UpgradeContext upgradeContext) throws Exception {
    if (upgradeContext == null) {
      throw new IllegalArgumentException("Upgrade context havent initialize!");
    }

    if (upgradeContext.getUpgradeConnection() == null) {
      throw new Exception("DB connection havent initialize!");
    }

    this.upgradeContext = upgradeContext;
  }

  public UpgradeState getUpgradeState() {
    return upgradeContext.getUpgradeState();
  }

  /**
   * <code>UpgradeHandler</code> added to this class shouldnt be
   * <code>null</code>, If the given <code>UpgradeHandler</code> is
   * <code>null</code>, just return <code>false</code>, nothing else
   * will to do.
   */
  public boolean addHandler(UpgradeHandler handler) {
    if (handler == null) {
      return false;
    }
    return (upgradeHandlersList.add(handler));
  }

  public boolean removeHandler(UpgradeHandler handler) {
    return (upgradeHandlersList.remove(handler));
  }

  public void addUpgradeExceptionHandler(UpgradeExceptionHandler exceptionHandler) {
    if (exceptionHandler == null) {
      throw new IllegalArgumentException("Can't add a null exceptionHandler to a upgrade handler!");
    }

    if (upgradeExceptionHandlersList == null) {
      upgradeExceptionHandlersList = new ArrayList();
    }

    upgradeExceptionHandlersList.add(exceptionHandler);
  }

  public void removeUpgradeExceptionHandler(UpgradeExceptionHandler exceptionHandler) {
    if (exceptionHandler == null) {
      throw new IllegalArgumentException("Can't remove a null exceptionHandler from a upgrade handler!");
    }

    if (upgradeExceptionHandlersList != null) {
      upgradeExceptionHandlersList.remove(exceptionHandler);
    }
  }

  public void raiseException(Throwable exception) throws UpgradeException {
    boolean isHandle = false;

    if (upgradeExceptionHandlersList != null) {
      try {
        UpgradeExceptionHandler exceptionHandler = findUpgradeExceptionHandler(exception);
        if (exceptionHandler != null) {
          upgradeContext.setException(exception);
          upgradeContext.setExceptionOccur(true);
          exceptionHandler.handleException(upgradeContext);
          isHandle = true;
        }
      } catch (Exception e) {
        exception = e;
      }
    }

    if (!isHandle) {
      UpgradeHandler topUpgradeHandler = upgradeContext.getTopUpgradeHandler();

      if (topUpgradeHandler != null && topUpgradeHandler != this) {
        topUpgradeHandler.raiseException(exception);
      } else {
        throw new UpgradeException(exception);
      }
    }

    // Throw the exception if it have been handle and upgrade completed flag
    // is true.
    if (isHandle && upgradeContext.isUpgradeCompleted()) {
      if (exception instanceof UpgradeException) {
        throw (UpgradeException) exception;
      }

      throw new UpgradeException(exception);
    }
  }

  /**
   * Update entry.
   */
  public void upgrade() {
    try {
      if (log.isDebugEnabled()) {
        log.debug(getClass().getName() + " begin to process upgradeBegin().");
      }
      upgradeBegin();
    } catch (Exception e) {
      log.error("Errors occurs at " + getClass().getName() + " processing upgradeBegin().", e);
      raiseException(e);
    }

    for (Iterator iter = upgradeHandlersList.iterator(); iter.hasNext();) {
      UpgradeHandler handler = (UpgradeHandler) iter.next();
      handler.upgrade();
    }

    try {
      if (log.isDebugEnabled()) {
        log.debug(getClass().getName() + " begin to process upgradeEnd().");
      }
      upgradeEnd();
    } catch (Exception e) {
      log.error("Errors occurs at " + getClass().getName() + " processing upgradeEnd().", e);
      raiseException(e);
    }
  }

  protected abstract void upgradeBegin() throws Exception;

  protected abstract void upgradeEnd() throws Exception;

  private UpgradeExceptionHandler findUpgradeExceptionHandler(Throwable exception) {
    if (upgradeExceptionHandlersList == null) {
      return (null);
    }

    UpgradeExceptionHandler exceptionHandler = null;
    for (Iterator exceptionHandlers = upgradeExceptionHandlersList.iterator(); exceptionHandlers.hasNext();) {
      UpgradeExceptionHandler candidate = (UpgradeExceptionHandler) exceptionHandlers.next();
      if (candidate.matches(exception)) {
        exceptionHandler = candidate;
        break;
      }
    }

    return (exceptionHandler);
  }
}
